package com.sparrow.example_message;

import com.baidu.bjf.remoting.protobuf.MessageGenerator;
import com.baidu.bjf.remoting.protobuf.ProtobufIDLGenerator;
import com.baidu.bjf.remoting.protobuf.annotation.ProtobufClass;
import com.sparrow.common.util.FileUtil;
import com.sparrow.common.util.PackageUtil;
import com.sparrow.common.util.RunTimeUtil;
import com.sparrow.socket.anno.Packet;
import org.apache.commons.io.FileUtils;

import java.io.File;
import java.io.IOException;
import java.lang.reflect.Field;
import java.nio.charset.Charset;
import java.nio.file.Paths;
import java.util.*;

public class MessageGenMain {
    private static final Map<Integer, String> idToName = new HashMap<>();

    private void scanPacketId() {
        // 扫描 PacketId 的所有内部类/接口
        for (Class<?> group : PacketId.class.getDeclaredClasses()) {
            for (Field field : group.getDeclaredFields()) {
                try {
                    if (field.getType() == int.class) {
                        int value = field.getInt(null);
                        // 存储为 RESP_LOGIN_PACKET 这种格式
                        String name = field.getName();
                        idToName.put(value, name);
                    }
                } catch (Exception ignored) {}
            }
        }
    }


    public static void main(String[] args) throws Exception {
        MessageGenMain main = new MessageGenMain();
        main.scanPacketId();

        Set<Class<?>> classes = PackageUtil.scanClass("com.sparrow.example_message", classMetadata -> classMetadata.hasAnnotation(ProtobufClass.class.getName()));
        String classPath = MessageGenMain.class.getProtectionDomain().getCodeSource().getLocation().toURI().getPath();
        File targetDir = new File(classPath).getParentFile(); // 这是 target 目录
        File moduleRoot = targetDir.getParentFile();          // 向上一层，拿到模块根目录
        System.out.println("模块根目录: " + moduleRoot.getAbsolutePath());
        String projectPath = moduleRoot.getAbsolutePath();
        String protoPath = Paths.get(projectPath,"proto").toString();
        String clientProto = Paths.get(projectPath,"client_proto").toString();
        FileUtil.delete(new File(protoPath));
        System.out.println("清理 " + protoPath);
        FileUtil.delete(new File(clientProto));
        System.out.println("清理 " + clientProto);

        ProtobufIDLGenerator.basePackageInfo = "com.sparrow.example_message";
        Collection<Class<?>> clazzs = new MessageGenerator().generate(classes, moduleRoot.getAbsolutePath());
        genClientPacketId(clazzs, moduleRoot.getAbsolutePath());

        //执行生成C# Proto代码
        if (RunTimeUtil.isWindows()) {
           RunTimeUtil.runBat(moduleRoot +File.separator +"proto.cmd");
        }
    }

    private static void genClientPacketId(Collection<Class<?>> clazzs, String projectPath) {
        //生成前端C# PacketId 类内容
        StringBuilder packetIdSb = new StringBuilder();
        packetIdSb.append("using System.Collections;\n");
        packetIdSb.append("using System.Collections.Generic;\n");
        packetIdSb.append("using UnityEngine;\n");
        packetIdSb.append("using Google.Protobuf;\n");
        packetIdSb.append("\n");
        packetIdSb.append("public class PacketId\n");
        packetIdSb.append("{\n");

        List<PacketIdFieldInfo> fieldInfos = new ArrayList<>();
        for (Class<?> clazz : clazzs) {
            Packet an = clazz.getAnnotation(Packet.class);
            if (an == null) {
                continue;
            }
            PacketIdFieldInfo fieldInfo = new PacketIdFieldInfo();
            int msgId = an.msgId();
            fieldInfo.msgId = msgId;
            fieldInfo.fieldName = getName(msgId);
            ProtobufClass protoAn = clazz.getAnnotation(ProtobufClass.class);
            fieldInfo.fieldDesc = protoAn.description();
            fieldInfo.clazzName = clazz.getSimpleName();
            fieldInfos.add(fieldInfo);
        }

        fieldInfos.sort(Comparator.comparingInt(o -> o.msgId));

        for (PacketIdFieldInfo f : fieldInfos) {
            packetIdSb.append("\t//").append(f.fieldDesc).append("\n");
            packetIdSb.append("\tpublic const int ").append(f.fieldName).append(" = ").append(f.msgId).append(";\n");
        }

        //
        packetIdSb.append("\tstatic PacketId()");
        packetIdSb.append("\t{\n");
        packetIdSb.append("\t\tinit();\n");
        packetIdSb.append("\t}\n");

        //生成 register
        packetIdSb.append("\n");
        packetIdSb.append("\tpublic static readonly Dictionary<int, MessageParser> parsers = new Dictionary<int, MessageParser>();").append("\n");
        packetIdSb.append("\tpublic static void init()").append("\n");
        packetIdSb.append("\t{").append("\n");
        //Register 代码
        for (PacketIdFieldInfo f : fieldInfos) {
            packetIdSb.append(String.format("\t\tRegister<Com.Sparrow.ExampleMessage.Proto.%s>(PacketId.%s);\n", f.clazzName, f.fieldName));
        }
        packetIdSb.append("\t}").append("\n");

        packetIdSb.append("\tpublic static void Register<T>(int msgId) where T : IMessage<T>, new()\n\t{\n");
        packetIdSb.append("\t\tparsers[msgId] = new MessageParser<T>(() => new T());\n");
        packetIdSb.append("\t}\n");
        packetIdSb.append("}");

        String protoPath = Paths.get(projectPath,"client_proto").toString();
        File file = new File(protoPath + File.separator + "PacketId.cs");
        System.out.println(file.getAbsolutePath());
        try {
            FileUtils.writeStringToFile(file, packetIdSb.toString(), Charset.forName("UTF8"));
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    private static class PacketIdFieldInfo {
        public int msgId;
        public String fieldName;
        public String fieldDesc;
        public String clazzName;
    }


    public static String getName(int id) {
        return idToName.get(id);
    }


}
